package com.newbee.builder;

import cn.hutool.core.util.IdUtil;
import com.google.common.collect.ImmutableMap;
import com.newbee.enums.TraceNodeEnum;
import com.newbee.model.TraceContext;
import com.newbee.model.TraceNode;
import com.newbee.utils.SensitiveUtil;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import javax.annotation.Nonnull;
import javax.annotation.Resource;
import java.util.Date;
import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;

@Component
public class TraceNodeBuilder {

    @Resource(name = "warnThresholdsMap")
    private ImmutableMap<String, Long> warnThresholdsMap;

    @Nonnull
    public TraceNode buildAsyncNode(@Nonnull TraceContext mainContext) {
        TraceNode node = new TraceNode();
        node.setNodeId(IdUtil.fastSimpleUUID());
        node.setTraceId(mainContext.getTraceId());
        node.setStatus(TraceNodeEnum.PENDING);
        node.setCreateTime(new Date());
        node.setChildren(new CopyOnWriteArrayList<>());
        node.setAsync(true);
        node.setClassName("异步节点");
        node.setMethodName("处理中");
        return node;
    }

    @Nonnull
    public TraceNode buildTraceNode(@Nonnull TraceContext context, @Nonnull ProceedingJoinPoint joinPoint) {
        TraceNode node = new TraceNode();
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        String methodName = signature.getName();
        String className = signature.getDeclaringTypeName();

        // 同步线程下, 不涉及线程上下文信息透传, 自动生成
        String asyncRootNodeId = context.getAsyncRootNodeId();
        if (StringUtils.isBlank(asyncRootNodeId)) {
            node.setNodeId(IdUtil.fastSimpleUUID());
        }
        // 如果是异步线程, ThreadLocal 会透传异步节点对应的 nodeId, 作为根节点id, 注意需要清理, 避免后续污染节点
        else {
            node.setNodeId(asyncRootNodeId);
            node.setAsync(true);
            context.clearAsyncRootNodeId();
        }
        node.setTraceId(context.getTraceId());
        node.setStatus(TraceNodeEnum.RUNNING);
        node.setClassName(className);
        node.setMethodName(methodName);
        node.setRequestParam(SensitiveUtil.desensitize(joinPoint.getArgs()));
        node.setCreateTime(new Date());
        node.setUpdateTime(new Date());
        long threshold = Objects.requireNonNull(
                warnThresholdsMap.getOrDefault(node.getMethodPath(), 500L),
                "阈值不可能为null"
        );
        node.setWarnThreshold(threshold);
        node.setChildren(new CopyOnWriteArrayList<>());
        return node;
    }

}
